/*
 * @Author: zs.duan
 * @Date: 2023-05-01 18:08:44
 * @LastEditors: zs.duan
 * @LastEditTime: 2023-11-10 21:42:50
 * @FilePath: \serve\routes\userApi.js
 */
const express = require("express");
const router = express.Router();
const Db = require("../utils/db");
const createSql = require("../utils/Create_SQL");
const path = require('path');
const fs = require('fs');
const { errorCode, successCode, config } = require('../config/config');
const request = require("request");
const utils = require("../utils/utils.js")

/**
 * @swagger
 * /api/users/adminLogin:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 用户登录-后台
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                user_login:
 *                  type: string
 *                  description: 加密后的用户名和密码以及是否扫码登录
 *                pwd_login:
 *                  type: string
 *                  description: 加密后的验证码
 *                code:
 *                  type: string
 *                  description: 未加密验证码
 *                ua:
 *                  type: string
 *                  description: 设备信息
 *      responses:
 *        200:
 *          description: 返回结果
 * */

/**
 * 加密数据
 * {
    "user_login": "HR0fAE8z2VeP4Ylj9AZtv6C6qUEmUwHR8kaQz3+dZkEWi6iTfCS17iZnuU5CFhoM",
    "timestamp": 1687664215330,
    "pwd_login": "pto6Mbp2b2O9y1BVB4iGhw==",
    "code": "7kmm",
    "ua": "{\"browserName\":\"Chrome\",\"browserVersion\":\"114.0.0.0\",\"osName\":\"Windows\",\"osVersion\":\"10.0\",\"deviceName\":\"\"}"
}
 * */
router.post("/adminLogin", async (req, res) => {
    let { user_login, pwd_login, code, ua } = req.body;
    if (!user_login || !pwd_login) {
        res.status(500);
        res.send({
            ...errorCode[10003]
        })
        return;
    }
    // 清除cookie
    res.clearCookie('token');
    let userInfo = utils.ACEdecrypt({ word: user_login, type: "object" });
    let newCode = utils.ACEdecrypt({ word: pwd_login });
    if (JSON.stringify(code) != newCode) {
        res.status(500);
        return res.send({
            ...errorCode[10016]
        })
    }
    let password = userInfo.is_scan ? userInfo.passwrod : utils.MD5({ word: userInfo.passwrod });
    let sql = createSql.select().from("user_admin").where(`user_name = '${userInfo.user_name}' and password = '${password}'`).end();
    let data = await Db.query(sql, res);
    if (data.length == 0) {
        res.status(500);
        return res.send({
            ...errorCode[10012]
        })
    }
    data = data[0];
    if (data.is_disable != '0') {
        res.status(500);
        return res.send({
            ...errorCode[10010],
            message: "该用户已被禁用"
        })
    }
    // 限制一个ip 一个设备只能登录一个账号
    let ip = utils.getClientIP(req);
    // let token = utils.GenerateSecretKey(data, config.secretOrPrivateKey);
    let { token } = data;
    if (!ua) {
        res.status(500);
        return res.send({
            ...errorCode[10000],
            message: "未知设备,无法登录"
        })
    }
    let { loginIP } = data;
    let date_ua = data.ua;
    // 设备和ip不同则重新生成token
    let tokenJson = {
        ID: data.ID,
        user_name: data.user_name,
        password: data.password,
    }
    if (JSON.stringify(ua) != date_ua || loginIP != ip) {
        token = utils.GenerateSecretKey(tokenJson, config.secretOrPrivateKey);
    }
    // 更新登录记录
    sql = createSql.update("user_admin").set({ loginIP: ip, ua: JSON.stringify(ua), token: token, lastLoginTime: utils.getTime("yyyy-MM-dd HH:mm:ss") }).where(`ID = '${data.ID}'`).end();
    let reslut = await Db.query(sql, res);
    if (reslut.code > 200) {
        return;
    }

    res.cookie('token', token, { maxAge: 1000 * 60 * 60 * 24 * 1, httpOnly: true });
    return res.json({
        ...successCode[200],
        token: token,
        user_name: data.user_name,
        data: {
            power: data.power,
            ua: ua
        }
    })
})

/**
 * @swagger
 * /api/user/scanAdminLogin:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 扫码登录-后台
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                userInfo:
 *                  type: object
 *                  description: 加密后的验证码
 *                code:
 *                  type: string
 *                  description: 扫码的code
 *      responses:
 *        200:
 *          description: 返回结果
 * */

router.post("/scanAdminLogin", async (req, res) => {
    const { code, userInfo } = req.body;
    if (!code) {
        res.status(500);
        return res.json({
            ...errorCode[10003]
        })
    }
    // 查询 二维码是否被使用过
    let sql = createSql.select().from("scan_login_info").where(`code = '${code}'`).end();
    let data = await Db.query(sql, res);
    if (data.code) return;
    if (data.length) {
        res.status(500);
        return res.json({
            ...errorCode[10010],
            message: "二维码已被扫描过啦"
        })
    }
    // 查询 登录的账号是否存在
    sql = createSql.select().from("web_userinfo").where(`ID = '${userInfo.ID}'`).end();
    let web_user_data = await Db.query(sql, res);
    if (web_user_data.data) return;
    if (!web_user_data.length) {
        res.status(500);
        return res.json({
            ...errorCode[10010],
            message: "账号不存在"
        })
    }
    web_user_data = web_user_data[0];
    if (!web_user_data.admin_user_id) {
        res.status(500);
        return res.json({
            ...errorCode[10010],
            message: "该账号不属于管理员账号"
        })
    }
    sql = createSql.select().from("user_admin").where(`ID = '${web_user_data.admin_user_id}'`).end();
    let user_admin_data = await Db.query(sql, res);
    if (user_admin_data.code) return;
    if (!user_admin_data.length) {
        res.status(500);
        return res.json({
            ...errorCode[10010],
            message: "账号不存在"
        })
    }
    user_admin_data = user_admin_data[0];
    if (user_admin_data.is_disable != '0' || user_admin_data.is_stop) {
        res.status(500);
        return res.send({
            ...errorCode[10010],
            message: "该用户已被禁用"
        })
    }
    let admin_data = {
        ID: user_admin_data.ID,
    }
    let isnetData = {
        addtime: utils.getTime(),
        ID: utils.getUuid(),
        userInfo: JSON.stringify(admin_data),
        scan_ip: utils.getClientIP(req),
        type: "0",
        code: code,
    }
    sql = createSql.insert("scan_login_info").value(isnetData).end();
    Db.query(sql);
    return res.json({
        ...successCode[200]
    })
})

/**
 * @swagger
 * /api/user/getScanLoginResult:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 扫码登录状态-查询
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                code:
 *                  type: string
 *                  description: 扫码的code
 *      responses:
 *        200:
 *          description: 返回结果
 * */

router.post("/getScanLoginResult", async (req, res) => {
    const { code } = req.body;
    if (!code) {
        res.status(500);
        return res.json({
            ...errorCode[10003]
        })
    }
    // 查询二维码是否被扫描
    let sql = createSql.select().from("scan_login_info").where(`code = '${code}'`).end();
    let data = await Db.query(sql, res);
    if (data.code) return;
    if (!data.length) {
        return res.json({
            ...successCode[200],
            message: "用户未扫码",
            type: "0"
        })
    }
    data = data[0];
    if (data.is_expired == '1') {
        res.status(500);
        return res.json({
            ...errorCode[10002],
            message: "二维码已过期"
        })
    }
    sql = createSql.update("scan_login_info").set({ is_expired: "1" }).where(`code = '${data.code}'`).end();
    await Db.query(sql, res);
    return res.json({
        ...successCode[200],
        type: "1",
        data: utils.ACEencrypt({ word: data.userInfo })
    })
})

/**
 * @swagger
 * /api/users/webLogin:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 用户登录-web
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                userLogin:
 *                  type: string
 *                  description: 加密后的用户名和密码以及是否扫码登录
 *                ua:
 *                  type: string
 *                  description: 设备信息
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/webLogin", async (req, res) => {
    const { userLogin, ua } = req.body;
    if (!userLogin) {
        return res.json({
            ...errorCode[10003]
        })
    }
    if (!ua) {
        return res.json({
            ...errorCode[10000],
            message: "未知设备,无法登录"
        })
    }
    let userInfo = utils.ACEdecrypt({ word: userLogin, type: "object" });
    let sql = "";
    // 验证码登录
    if (userInfo.code) {
        sql = createSql.select().from("code_expires").where(`name = '${userInfo.username}' and code = '${userInfo.code}'`).end();
        let result = await Db.query(sql, res);
        if (result.code > 200) return;
        let data = result[0];
        if (!data) {
            return res.json({
                ...errorCode[10001]
            })
        }
        if (data.expires < new Date().getTime()) {
            sql = createSql.update('code_expires').set({ isExpire: 1 }).where(`name = '${userInfo.username}' and code = '${userInfo.code}'`).end();
            result = await Db.query(sql, res);
            return res.json({
                ...errorCode[10010],
                message: "验证码已过期"
            })
        }
        sql = createSql.delete('code_expires').where(`name = '${userInfo.username}' and code = '${userInfo.code}'`).end();
        result = await Db.query(sql, res);
        if (result.code > 200) return;
        sql = createSql.select().from("web_userinfo").where(`email = '${userInfo.username}' and is_del != '1'`).end();
        data = await Db.query(sql, res);
        if (data.length == 0) {
            res.status(500);
            return res.json({
                ...errorCode[10012]
            })
        }
        data = data[0];
        handleLoginSuccess(data, req, res, ua);
        return;
    }

    // 账号密码登录
    let password = userInfo.is_scan ? userInfo.passwrod : utils.MD5({ word: userInfo.password });
    sql = createSql.select().from("web_userinfo").where(`username = '${userInfo.username}'
    or email = '${userInfo.username}' 
    or tel = '${userInfo.username}'
    and password = '${password}' and is_del != '1'`).end();
    let data = await Db.query(sql, res);
    if (data.length == 0) {
        res.status(500);
        return res.json({
            ...errorCode[10012]
        })
    }
    data = data[0];
    handleLoginSuccess(data, req, res, ua);
});

/**处理登录成功后 -用户*/
const handleLoginSuccess = async (data, req, res, ua) => {
    let ip = utils.getClientIP(req);
    if (data.is_stop != '0') {
        res.status(500);
        return res.json({
            ...errorCode[10010],
            message: "该用户已被禁用"
        })
    }
    res.clearCookie('token');
    let tokenJson = {
        ID: data.ID,
        username: data.username,
        password: data.password,
    }
    let token = utils.GenerateSecretKey(tokenJson, config.secretOrPrivateKey);
    sql = createSql.update("web_userinfo").set({ loginIP: ip, ua: ua, lastLoginTime: utils.getTime("yyyy-MM-dd HH:mm:ss") }).where(`ID = '${data.ID}'`).end();
    let reslut = await Db.query(sql, res);
    if (reslut.code > 200) {
        return;
    }
    res.cookie('token', token, { maxAge: 1000 * 60 * 60 * 24 * 1, httpOnly: true });
    delete data.password;
    return res.json({
        ...successCode[200],
        token: token,
        data: data
    })
}

/**
 * @swagger
 * /api/users/webLoginOut:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 用户退出登录-web
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/webLoginOut", async (req, res) => {
    res.clearCookie('token');
    return res.json({
        ...successCode[200]
    })
})


/**
 * @swagger
 * /api/users/register:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 用户注册-web
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                username:
 *                  required: true
 *                  type: string
 *                  description: 用户名
 *                password:
 *                  required: true
 *                  type: string
 *                  description: 密码
 *                code:
 *                  required: true
 *                  type: string
 *                  description: 验证码
 *                email:
 *                  required: true
 *                  type: string
 *                  description: 邮箱
 *                tel:
 *                  type: string
 *                  description: 手机号
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/register", async (req, res) => {
    let { username, password, code, email, tel } = req.body;
    if (!username || !password || !code || !email) {
        res.status(500);
        return res.json({
            ...errorCode[10003]
        })
    }
    let sql = createSql.select().from("code_expires").where(`name = '${email}' and code = '${code}'`).end();
    let result = await Db.query(sql, res);
    if (result.code > 200) return;
    let data = result[0];
    if (!data) {
        return res.json({
            ...errorCode[10001],
            message: "验证码错误"
        })
    }
    if (data.expires < new Date().getTime()) {
        return res.json({
            ...errorCode[10010],
            message: "验证码已过期"
        })
    }
    sql = createSql.update('code_expires').set({ isExpire: 1 }).where(`name = '${email}' and code = '${code}'`).end();
    result = await Db.query(sql, res);
    if (result.code > 200) return;
    sql = createSql.select().from("web_userinfo").where(`username = '${username}' or email = '${email}'`).end();
    data = await Db.query(sql, res);
    if (data.length > 0) {
        return res.json({
            ...errorCode[10010],
            message: "用户名或邮箱已存在"
        })
    }
    sql = createSql.insert('web_userinfo').value({
        ID: utils.getUuid(),
        icon: '/img/user-icon.png',
        username: username,
        password: utils.MD5({ word: password }),
        email: email,
        tel: tel,
        addtime: utils.getTime(),
        loginIP: utils.getClientIP(req),
        lastLoginTime: utils.getTime("yyyy-MM-dd HH:mm:ss")
    }).end();
    result = await Db.query(sql, res);
    if (result.code > 200) return;
    return res.json({
        ...successCode[200]
    })
})

/**
 * @swagger
 * /api/users/webResetPassword:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 用户重置密码-web
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                email:
 *                  required: true
 *                  type: string
 *                  description: 邮箱
 *                code:
 *                  required: true
 *                  type: string
 *                  description: 验证码
 *                password:
 *                  required: true
 *                  type: string
 *                  description: 密码
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/webResetPassword", async (req, res) => {
    let { email, code, password } = req.body;
    if (!email || !code || !password) {
        return res.json({
            ...errorCode[10003]
        })
    }
    let sql = createSql.select().from("code_expires").where(`name = '${email}' and code = '${code}' and isExpire = 0`).end();
    let result = await Db.query(sql, res);
    if (result.code > 200) return;
    let data = result[0];
    if (!data) {
        return res.json({
            ...errorCode[10016],
            message: "验证码错误"
        })
    }
    if (data.expires < new Date().getTime()) {
        return res.json({
            ...errorCode[10016],
            message: "验证码已过期"
        })
    }
    sql = createSql.update('code_expires').set({ isExpire: 1 }).where(`name = '${email}' and code = '${code}'`).end();
    result = await Db.query(sql, res);
    if (result.code > 200) return;
    sql = createSql.update('web_userinfo').set({ password: utils.MD5({ word: password }) }).where(`email = '${email}'`).end();
    result = await Db.query(sql, res);
    if (result.code > 200) return;
    return res.json({
        ...successCode[200]
    })
})

/**
 * @swagger
 * /api/users/wxLogin:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 用户登录-微信小程序
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                username:
 *                  required: true
 *                  type: string
 *                  description: 用户名
 *                password:
 *                  required: true
 *                  type: string
 *                  description: 密码
 *                code:
 *                  required: true
 *                  type: string
 *                  description: 验证码
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/wxLogin", async (req, res) => {
    let { username, password, code } = req.body;
    if (!username) {
        return res.json({
            ...errorCode[10003]
        })
    }
    if (code) {
        let sql = createSql.select().from("code_expires").where(`name = '${username}' and code = '${code}'`).end();
        let result = await Db.query(sql, res);
        if (result.code > 200) return;
        let data = result[0];
        if (!data) {
            return res.json({
                ...errorCode[10001]
            })
        }
        if (data.expires < new Date().getTime()) {
            sql = createSql.update('code_expires').set({ isExpire: 1 }).where(`name = '${username}' and code = '${code}'`).end();
            result = await Db.query(sql, res);
            return res.json({
                ...errorCode[10010],
                message: "验证码已过期"
            })
        }
        sql = createSql.update('code_expires').set({ isExpire: 1 }).where(`name = '${username}' and code = '${code}'`).end();
        result = await Db.query(sql, res);
        if (result.code > 200) return;
        sql = createSql.select().from("web_userinfo").where(`email = '${username}' and is_del != '1'`).end();
        data = await Db.query(sql, res);
        if (data.length == 0) {
            res.status(500);
            return res.json({
                ...errorCode[10012]
            })
        }
        data = data[0];
        handleLoginSuccess(data, req, res);
        return;
    }
    password = utils.MD5({ word: password });
    let sql = createSql.select().from("web_userinfo").where(`username = '${username}'
    or email = '${username}'
    or tel = '${username}'
    and password = '${password}' and is_del != '1'`).end();
    let data = await Db.query(sql, res);
    if (data.length == 0) {
        res.status(500);
        return res.json({
            ...errorCode[10012]
        })
    }
    data = data[0];
    handleLoginSuccess(data, req, res);
})

/**
 * @swagger
 * /api/users/updateUserInfo:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 修改用户信息
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                username:
 *                  type: string
 *                  description: 用户名
 *                tel:
 *                  type: string
 *                  description: 用户名
 *                icon:
 *                  type: string
 *                  description: 用户名
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/updateUserInfo", async (req, res) => {
    let { username, tel, icon, ID } = req.body;
    if (!ID || (!username && !tel && !icon)) {
        return res.json({
            ...errorCode[10003]
        })
    }
    let set = {};
    if (username) set.username = username;
    if (tel) set.tel = tel;
    if (icon) set.icon = icon;
    let sql = createSql.update('web_userinfo').set(set).where(`ID = '${ID}'`).end();
    let result = await Db.query(sql, res);
    if (result.code > 200) return;
    return res.json({
        ...successCode[200]
    })
})

/**
 * @swagger
 * /api/users/updateEmail:
 *    post:
 *      tags:
 *      - 用户相关
 *      summary: 修改/绑定邮箱
 *      produces:
 *      - application/json
 *      requestBody:
 *        description: Optional description in *Markdown*
 *        required: true
 *        content:
 *          application/json:
 *            schema:
 *              type: object
 *              properties:
 *                ID:
 *                  type: string
 *                  required: true
 *                  description: 用户ID
 *                email:
 *                  type: string
 *                  required: true
 *                  description: 用户名
 *                code:
 *                  type: string
 *                  required: true
 *                  description: 验证码
 *      responses:
 *        200:
 *          description: 返回结果
 * */
router.post("/updateEmail", async (req, res) => {
    let { email, code, ID } = req.body;
    if (!email || !code || !ID) {
        return res.json({
            ...errorCode[10003]
        })
    }
    let sql = createSql.select().from("code_expires").where(`name = '${email}' and code = '${code}'`).end();
    let result = await Db.query(sql, res);
    if (result.code > 200) return;
    let data = result[0];
    if (!data) {
        return res.json({
            ...errorCode[10001]
        })
    }
    if (data.expires < new Date().getTime()) {
        return res.json({
            ...errorCode[10010],
            message: "验证码已过期"
        })
    }
    sql = createSql.update('code_expires').set({ isExpire: 1 }).where(`name = '${email}' and code = '${code}'`).end();
    result = await Db.query(sql, res);
    if (result.code > 200) return;
    sql = createSql.update('web_userinfo').set({ email: email }).where(`ID = '${ID}'`).end();
    result = await Db.query(sql, res);
    if (result.code > 200) return;
    return res.json({
        ...successCode[200]
    })
})

/**
 * @swagger
 * /api/users/getUserTokenByWxUserId:
 *    get:
 *      tags:
 *      - 用户相关
 *      summary: 通过用户ID获取用户token
 *      produces:
 *      - application/json
 *      parameters:
 *        - name: wxUserId
 *          default: 10
 *          description: 微信用户id
 *          in: query
 *          required: true
 *          type: string
 *      responses:
 *        200:
 *         description: successful operation
 * */

router.get("/getUserTokenByWxUserId", async (req, res) => {
    let { wxUserId } = req.query;
    if (!wxUserId) {
        return res.json({
            ...errorCode[10003]
        })
    }
    let sql = createSql.select().from('web_userinfo').where(`ID = '${wxUserId}'`).build();
    let result = await Db.query(sql, res);
    if (result.code > 200) return;
    if (!result.length) {
        return res.json({
            ...errorCode[10012]
        })
    }
    let data = result[0];
    if (data.is_stop != '0') {
        res.status(500);
        return res.json({
            ...errorCode[10010],
            message: "该用户已被禁用"
        })
    }
    let tokenJson = {
        ID: data.ID,
        username: data.username,
        password: data.password,
    }
    let token = utils.GenerateSecretKey(tokenJson, config.secretOrPrivateKey);
    res.json({
        ...successCode[200],
        data: {
            token: token
        }
    })

})

module.exports = router;